﻿//-----------------------------------------------------------------------
// <copyright file="IIdentitySerializer.cs" company="CodePlex">
//     Copyright (c) Doug Holland, CodePlex. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace CodePlex.Diagnostics.Contracts
{
    using System;
    using System.IO;
    using System.Text;
    using System.Diagnostics;

    using System.Security.Principal;

    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Soap;

    /// <summary>
    /// Provides the ability to serialize and deserialize classes implementing the <see cref="T:System.Security.Principal.IIdentity"/> interface.
    /// </summary>
    internal static class IIdentitySerializer
    {
        #region internal static string Serialize(IIdentity identity)

        /// <summary>
        /// Serializes the specified <see cref="T:System.Security.Principal.IIdentity"/> instance to a Soap encoded message.
        /// </summary>
        /// <param name="identity">The <see cref="T:System.Security.Principal.IIdentity"/> instance to serialize.</param>
        /// <returns>A <see cref="T:System.String"/> containing the soap encoded <see cref="T:System.Security.Principal.IIdentity"/> instance, , or <c>null</c> if the supplied identity cannot be serialized.</returns>
        internal static string Serialize(IIdentity identity)
        {
            if (identity == null)
            {
                throw new ArgumentNullException("identity");
            }

            Type type = identity.GetType();

            // ensure that the IIdentity can be serialized, otherwise return null.
            if (!type.IsSerializable)
            {
                return null;
            }

            // ensure that the IIdentity is not a generic type, the Soap serializer does not support generic types.
            if (type.IsGenericType)
            {
                return null;
            }

            IFormatter formatter = new SoapFormatter() as IFormatter;

            using (MemoryStream stream = new MemoryStream())
            {
                // serialize the identity into a memory stream.
                formatter.Serialize(stream, identity);

                ASCIIEncoding encoding = new ASCIIEncoding();

                // reset the stream position to the beginning of the stream.
                stream.Seek(0, SeekOrigin.Begin);

                // read the stream into a byte array.
                byte[] buffer = new byte[stream.Length];
                stream.Read(buffer, 0, buffer.Length);

                // process the byte buffer into a string.
                return encoding.GetString(buffer);
            }
        }

        #endregion

        #region internal static IIdentity Deserialize(string soap)

        /// <summary>
        /// Deserializes a <see cref="T:System.Security.Principal.IIdentity"/> from the specified Soap encoded <see cref="T:System.String"/> instance. 
        /// </summary>
        /// <param name="soap">The <see cref="T:System.String"/> containing the Soap encoded <see cref="T:System.Security.Principal.IIdentity"/> instance.</param>
        /// <returns>The deserialized <see cref="T:System.Security.Principal.IIdentity"/> instance.</returns>
        internal static IIdentity Deserialize(string soap)
        {
            if (string.IsNullOrEmpty(soap))
            {
                throw new ArgumentException(SR.GetString(SR.InvalidSoapEncodedIIdentity), "soap");
            }

            IFormatter formatter = new SoapFormatter() as IFormatter;

            using (MemoryStream stream = new MemoryStream())
            {
                ASCIIEncoding encoding = new ASCIIEncoding();

                // read the Soap encoded string into a byte array.
                byte[] buffer = encoding.GetBytes(soap);

                // write the byte array into the memory stream.
                stream.Write(buffer, 0, buffer.Length);

                // reset the stream position to the beginning of the stream.
                stream.Seek(0, SeekOrigin.Begin);

                // deserialize the identity from the memory stream.
                return formatter.Deserialize(stream) as IIdentity;
            }
        }

        #endregion
    }
}